#pragma once

#include <cstdint>

#include "Misc/CommonMacros.h"
#include "Containers/Vector.h"
#include "Containers/String.h"

class CProperty;
class CNativeFieldProperty;
class CType;


class WHENGINE_API CPropertyList
{
public:
    CPropertyList(CType* InOwnerType);
    virtual ~CPropertyList(){};

    TVector<CProperty*> & GetProperties();

    const TVector<CProperty*> & GetFieldProperties() const { return FieldProperties; }

    const TVector<CProperty*> & GetStaticFieldProperties() const { return StaticFieldProperties; }

    const TVector<CProperty*> & GetNonStaticFieldProperties() const { return NonStaticFieldProperties; }

    uint64_t GetPropertyNum() const { return Properties.Num(); }

    uint64_t GetFieldNum() const { return FieldProperties.Num(); }

    CProperty* GetProperty(uint64_t Index);

    CProperty* FindProperty(const CString& InPropertyName);

    CNativeFieldProperty* FindNativeFieldPropertyByOffset(int64_t Offset);

    virtual void AddProperty(CProperty* InProperty);

    virtual bool IsScriptPropertyList() const { return false; }

    //copy properties from Src to Dest
    static void CopyProperties(
        const CPropertyList* Src
        , CPropertyList* Dest
        );

    //append properties from Src to Dest
    //@param bSort: if true, sort field properties by FieldIndex
    static void AppendProperties(
        const CPropertyList* Src
        , CPropertyList* Dest
        , bool bSort
        );

    void SetStringExpressionProperty(CProperty* InStringExpressionProperty) { StringExpressionProperty = InStringExpressionProperty; }
    CProperty* GetStringExpressionProperty() const { return StringExpressionProperty; }

    CType* GetOwnerType() const { return OwnerType; }

    uint64_t GetNonStaticFieldHash(const void* InInstance) const;
    bool IsNonStaticFieldEqual(const void* A, const void* B) const;
protected:
    CType* OwnerType;

    //all properties
    TVector<CProperty*> Properties;
    
    //all field properties
    TVector<CProperty*> FieldProperties;

    //all static field properties
    TVector<CProperty*> StaticFieldProperties;

    //all non-static field properties
    TVector<CProperty*> NonStaticFieldProperties;

    //the property that is used to serialize this type to string
    //and deserialize this type from string
    CProperty* StringExpressionProperty=nullptr;
};